import {
  createContext,
  useReducer,
  useContext,
  useMemo,
  useEffect,
  useState,
  Dispatch,
} from 'react';
import BaseLayout from '../../components/BaseLayout';

interface Product {
  id?: number;
  name?: string;
  price?: number;
  // 件数
  count?: number;
}

enum ShoppingCartActionType {
  add,
  remove,
}

const ShoppingCartContext = createContext<
  | [Product[], Dispatch<{ type: ShoppingCartActionType; payload: Product }>]
  | undefined
>(undefined);

// 添加商品到购物册
const handleAddProduct = (list: Product[], product: Product) => {
  const _list = [...list];
  const matchedIdx = _list.findIndex((e) => e.id === product.id);

  if (matchedIdx != -1) {
    const copy = { ..._list[matchedIdx] };
    copy.count! += 1;
    _list.splice(matchedIdx, 1, copy);
  } else {
    _list.push(product);
  }

  return _list;
};

// 删除购物车商品
const handleDelProduct = (list: Product[], product: Product) => {
  const _list = [...list];
  const matchedIdx = _list.findIndex((e) => e.id === product.id);

  if (matchedIdx == -1) {
    return _list;
  }

  const copy = { ..._list[matchedIdx] };

  if (copy.count! > 1) {
    copy.count! -= 1;
    _list.splice(matchedIdx, 1, copy);
  } else {
    _list.splice(matchedIdx);
  }

  return _list;
};

const reducer = (
  s: Product[],
  action: { type: ShoppingCartActionType; payload: Product },
) => {
  switch (action.type) {
    case ShoppingCartActionType.add:
      // 添加
      var _s = handleAddProduct(s, action.payload);
      return _s;

    case ShoppingCartActionType.remove:
      // 删除
      var _s = handleDelProduct(s, action.payload);
      return _s;
  }
};

export default () => {
  const [products, setProducts] = useState<Product[] | undefined>();
  const r = useReducer(reducer, []);

  useEffect(() => {
    setProducts([
      { id: 1, name: 'a', price: 1, count: 1 },
      { id: 2, name: 'b', price: 2, count: 1 },
      { id: 3, name: 'c', price: 3, count: 1 },
    ]);
  }, []);

  return (
    <BaseLayout>
      <div className='shopping-cart'>
        <h3>购物车例子（主要 context 的运用）</h3>
        <ShoppingCartContext.Provider value={r}>
          <Catalog productList={products} />
          <Cart />
        </ShoppingCartContext.Provider>
      </div>
    </BaseLayout>
  );
};

/**
 * 目录
 */
const Catalog = ({ productList }: { productList?: Product[] }) => {
  return (
    <div className='catalog'>
      {productList?.map((e) => (
        <ProductItem key={e.id} {...e} />
      ))}
    </div>
  );
};

const ProductItem = (props: Product) => {
  const [_, dispatch] = useContext(ShoppingCartContext)!;

  // 添加
  const handleSelected = (e: Product) => {
    dispatch?.({ type: ShoppingCartActionType.add, payload: e });
  };

  return (
    <div className='product-item'>
      <div>
        商品名称：{props?.name} (¥{props.price}) -{' '}
        <button onClick={() => handleSelected(props)}>添加</button>
      </div>
    </div>
  );
};

const CartProductItem = (props: Product) => {
  const [_, dispatch] = useContext(ShoppingCartContext)!;
  return (
    <div className='product'>
      {props.name}（¥{props.price}） x {props.count}
      <button
        onClick={() =>
          dispatch({ type: ShoppingCartActionType.remove, payload: props })
        }
      >
        删除
      </button>
    </div>
  );
};

const Cart = () => {
  const [state] = useContext(ShoppingCartContext)!;
  // 购物车商品总价
  const totalPrice = useMemo(
    () => state?.reduce((prev, cur) => prev + cur.price! * cur.count!, 0),
    [state],
  );

  return (
    <div className='cart'>
      <h3>购物车</h3>
      {state?.map((e) => (
        <CartProductItem key={e.id} {...e} />
      ))}
      <div>价格:{totalPrice}元</div>
    </div>
  );
};
